
// VS_BEGIN
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aCoord;
layout (location = 2) in vec3 aNormal;
layout (location = 3) in vec3 aTangent;
layout (location = 4) in vec3 aBitangent;

uniform mat4 u_model;
uniform mat3 u_modelT;

layout (std140) uniform EngineUBO
{
    mat4 u_view;
    mat4 u_project;
    vec3 u_camPos;
    vec3 u_camInfo;
    mat4 u_inversePV;
};

out vec2 g_coord;
out vec3 g_position;
out vec3 g_normal;
out vec3 g_tangent;
out mat3 TBN;

void main() {
    g_coord = aCoord;
    g_position = vec3(u_model * vec4(aPos, 1.0f));
    g_normal = normalize(u_modelT * aNormal);
    g_tangent = normalize(vec3(u_model * vec4(aTangent, 0.0f)));
    gl_Position = u_project * u_view * u_model * vec4(aPos, 1.0f);
    vec3 T = normalize(vec3(u_model * vec4(aTangent,   0.0)));
    vec3 B = normalize(vec3(u_model * vec4(aBitangent, 0.0)));
    vec3 N = normalize(vec3(u_model * vec4(aNormal,    0.0)));
    TBN = mat3(T, B, N);
}
// VS_END
// FS_BEGIN
#version 330 core 
layout (location = 0) out vec4 PositionMetalRT;
layout (location = 1) out vec4 AlbedoRoughRT;
layout (location = 2) out vec4 NormalDepthRT;

// Light Packet:
// position.x position.y position.z type(PointLight: 0; DirectLight: 1; AmbientSphereLight: 2)
// color.r    color.g    color.b    strength
// direct.x   direct.y   direct.z   unuse
// unuse      unuse      unuse      unuse
layout (std140) uniform LightUBO
{
    mat4 u_lights[64];
    int u_lightNum;
};

layout (std140) uniform EngineUBO
{
    mat4 u_view;
    mat4 u_project;
    vec3 u_camPos;
    vec3 u_camInfo;
    mat4 u_inversePV;
};

out vec4 FragColor;

in vec2 g_coord;
in vec3 g_position;
in vec3 g_normal;
in vec3 g_tangent;
in mat3 TBN;

// Texture Offset
uniform vec2 Offset;
uniform vec2 Tiling;

// material parameters
uniform sampler2D   AlbedoMap;
uniform vec3        Albedo;
uniform sampler2D   MetallicMap;
uniform float       Metallic;
uniform sampler2D   RoughnessMap;
uniform float       Roughness;
uniform sampler2D   NormalMap;

uniform float UseAlbedoMap;
uniform float UseMetallicMap;
uniform float UseRoughnessMap;
uniform float UseNormalMap;

vec3 NormalMapToWorldSpace(vec3 v) {
    v = v * 2.0f - 1.0f;
    return TBN * v;
}

void main() {
    vec2 uv = g_coord * Tiling + Offset;

    vec3 albedo = mix(Albedo, texture(AlbedoMap, uv).xyz, UseAlbedoMap);
    vec3 normal = normalize(mix(g_normal, NormalMapToWorldSpace(texture(NormalMap, uv).xyz), UseNormalMap));
    float metallic = mix(Metallic, texture(MetallicMap, uv).x, UseMetallicMap);
    float roughness = mix(Roughness, texture(RoughnessMap, uv).x, UseRoughnessMap);
    PositionMetalRT = vec4(g_position.xyz, roughness);
    AlbedoRoughRT = vec4(albedo, metallic);
    NormalDepthRT = vec4(normal, gl_FragDepth);
}
// FS_END
